/**HEADER********************************************************************
* 
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
*************************************************************************** 
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: lwgpio_mpc8308.c$
* $Version : 3.8.3.0$
* $Date    : Sep-29-2011$
*
* Comments:
*
*   This file contains the GPIO standard functions used on boards
*
*END************************************************************************/

#include "mqx.h"
#include "bsp.h"
#include "lwgpio.h"

enum  { 
   PORTA =1,
   PORTB,
   ESDHCA,
   ESDHCB,
   ESDHCC,
   IEEEA,
   GTM,
   IEEEB,
   ETSEC2,
   
};
#define LWGPIO_PIN_FROM_ID(id) (((id) & LWGPIO_PIN_MASK) >> LWGPIO_PIN_SHIFT)
#define LWGPIO_PORT_FROM_ID(id) (((id) & LWGPIO_PORT_MASK) >> LWGPIO_PORT_SHIFT)

/* Interrupt mode definitions */
#define LWGPIO_INT_MODE_SHIFT (16) /* place it here to have on the same place as PCR_IRQC */
#define LWGPIO_INT_MODE_MASK (0x0F << LWGPIO_INT_MODE_SHIFT)
#define LWGPIO_INT_MODE(x) (((x) << LWGPIO_INT_MODE_SHIFT) & LWGPIO_INT_MODE_MASK)
#define LWGPIO_INT_MODE_FROM_ID(id) (((id) & LWGPIO_INT_MODE_MASK) >> LWGPIO_INT_MODE_SHIFT)

/* Direction field definitions */
#define LWGPIO_DIR_SHIFT (20)
#define LWGPIO_DIR_MASK (0x01 << LWGPIO_DIR_SHIFT)

static volatile MPC83xx_GPIO_STRUCT_PTR gpio_ptr;


/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_init
* Returned Value   : TRUE if succesfull, FALSE otherwise
* Comments         :
*    Decodes ID to HW specific struct and then performs pin initialization
*
*END*********************************************************************/
boolean lwgpio_init
(
    /* Pointer to LWGPIO internal structure to be filled in */
    LWGPIO_STRUCT_PTR handle,
    /* Pin ID, bitmask integer value */
    LWGPIO_PIN_ID     id,
    /* Direction to be set within initialization */
    LWGPIO_DIR        dir,
    /* Value to be set within initialization */
    LWGPIO_VALUE      value
)
{ /* Body */
   uint_32                 immr;
   static boolean first_run = TRUE;
   
   if (first_run) {
      _PSP_GET_IMMR(immr);   
      gpio_ptr = (MPC83xx_GPIO_STRUCT_PTR)(immr + MPC83xx_GPIO1_BASE);
      first_run = FALSE;
   }
   handle->port_idx = LWGPIO_PORT_FROM_ID(id);
   handle->pinmask =  0x80000000 >> LWGPIO_PIN_FROM_ID(id);
   handle->flags = id;
   
   /* Set value prior to set to output */
   if (value != LWGPIO_VALUE_NOCHANGE) {
       /* Note: there is no check for values not defined as LWGPIO_VALUE enum */
       lwgpio_set_value(handle, value);
   }
   if (dir != LWGPIO_DIR_NOCHANGE) {
       /* Note: there is no check for values not defined as LWGPIO_DIR enum */
       lwgpio_set_direction(handle, dir);
   }
   return TRUE;
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_set_attribute
* Returned Value   : TRUE if succesfull, FALSE otherwise
* Comments         :
*    Sets attributes
*
*END*********************************************************************/
boolean lwgpio_set_attribute
(
    /* Pin handle to get function from */
    LWGPIO_STRUCT_PTR  handle,
    /* PORT attribute */
    uint_32 attribute_id,
    /* Attribute value */
    uint_32 value
)
{
    switch(attribute_id)
    {
        case(LWGPIO_ATTR_OPEN_DRAIN):
        {
            if(value == LWGPIO_AVAL_ENABLE)
            {
                gpio_ptr->ODR |= handle->pinmask;
            }
            else        /* value == LWGPIO_AVAL_DISABLE */
            {
                gpio_ptr->ODR &= ~(handle->pinmask);
            }
            break;
        }
        default:
        {
            return FALSE;
        }
    }
    return TRUE;
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_set_functionality
* Returned Value   : void
* Comments         :
*    Sets functionality (peripheral mode) of the pin
*
*END*********************************************************************/
void lwgpio_set_functionality
(
    /* Pin handle to set function on */
    LWGPIO_STRUCT_PTR  handle, 
    /* Function to be set (integer value) */
    uint_32            function
)
{ 
    MPC83xx_SYSCON_STRUCT_PTR    syscon_ptr;
    uint_32                      immr;
    
    immr = (uint_32)_mpc83xx_get_immr();
    syscon_ptr = (MPC83xx_SYSCON_STRUCT_PTR)(immr + MPC83xx_SYSCON_BASE);
    switch(handle->port_idx)
    {
       case PORTA :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_GPIO_A(3));
         syscon_ptr->SICRH |= (MPC8308_SYSCON_SICRH_GPIO_A(function));
         break;
       case PORTB :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_GPIO_B(3));
         syscon_ptr->SICRH |= (MPC8308_SYSCON_SICRH_GPIO_B(function));
         break;
       case ESDHCA :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_ESDHC_A(3));
         syscon_ptr->SICRH |= MPC8308_SYSCON_SICRH_ESDHC_A(function);
         break;
       case ESDHCB :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_ESDHC_B(3));
         syscon_ptr->SICRH |= MPC8308_SYSCON_SICRH_ESDHC_B(function);
         break;
       case LWGPIO_ESDHCC :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_ESDHC_C(3));
         syscon_ptr->SICRH |= MPC8308_SYSCON_SICRH_ESDHC_C(function);
         break;
       case IEEEA :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_IEEE1588_A(3));
         syscon_ptr->SICRH |= MPC8308_SYSCON_SICRH_IEEE1588_A(function);
         break;
       case GTM :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_GTM(3));
         syscon_ptr->SICRH |= MPC8308_SYSCON_SICRH_GTM(function);
         break;
       case IEEEB :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_IEEE1588_B(3));
         syscon_ptr->SICRH |= MPC8308_SYSCON_SICRH_IEEE1588_B(function);
         break;   
        case ETSEC2 :
         syscon_ptr->SICRH &= ~(MPC8308_SYSCON_SICRH_ETSEC2(3));
         syscon_ptr->SICRH |= MPC8308_SYSCON_SICRH_ETSEC2(function);
         break;
       default :
            break;
    }

   
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_get_functionality
* Returned Value   : void
* Comments         :
*    Gets functionality (peripheral mode) of the pin
*
*END*********************************************************************/
uint_32 lwgpio_get_functionality
(
    /* Pin handle to get function from */
    LWGPIO_STRUCT_PTR  handle
)
{
    
  /* Code will put here*/
   MPC83xx_SYSCON_STRUCT_PTR    syscon_ptr;
   uint_32                      immr;
   uint_32                      retval;
    
   immr = (uint_32) _mpc83xx_get_immr();
   syscon_ptr = (MPC83xx_SYSCON_STRUCT_PTR)(immr + MPC83xx_SYSCON_BASE);    
   switch(handle->port_idx)
   {
     case PORTA :
        retval = ((syscon_ptr->SICRH) & (MPC8308_SYSCON_SICRH_GPIO_A(3))>>24);
        break;
    case PORTB :
        retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_GPIO_B(3))>>22);     
        break;
      case ESDHCA :
        retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_ESDHC_A(3))>>30);     
        break;
      case ESDHCB :
         retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_ESDHC_B(3))>>28);     
        break;
      case LWGPIO_ESDHCC :
          retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_ESDHC_C(3))>>26);     
        break;
      case IEEEA :
         retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_IEEE1588_A(3))>>20);              
         break;
      case GTM :
         retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_GTM(3))>>16);                       
         break;
      case IEEEB :
        retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_IEEE1588_B(3))>>14);                                
        break;   
      case ETSEC2 :
         retval = ((syscon_ptr->SICRH) &(MPC8308_SYSCON_SICRH_ETSEC2(3))>>12);                                          
         break;
      default :
         break;
   }
   return retval; 
   
}


/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_set_direction
* Returned Value   : void
* Comments         :
*    Sets direction of the pin
*
*END*********************************************************************/
void lwgpio_set_direction
(
    /* Pin handle to set direction on */
    LWGPIO_STRUCT_PTR  handle, 
    /* Direction to be set */
    LWGPIO_DIR         dir
)
{
    if (dir == LWGPIO_DIR_INPUT) {
        gpio_ptr->DIR &= ~(handle->pinmask);
    }
    else if (dir == LWGPIO_DIR_OUTPUT) {
        gpio_ptr->DIR |= handle->pinmask;
    }
    else { /* LWGPIO_DIR_NOCHANGE or other value */
    }
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_set_value
* Returned Value   : void
* Comments         :
*    Sets value (output latch) of the pin
*
*END*********************************************************************/
void lwgpio_set_value
(
    /* Pin handle to set value on */
    LWGPIO_STRUCT_PTR  handle, 
    /* Direction to be set */
    LWGPIO_VALUE       out_value
)
{
    if (out_value == LWGPIO_VALUE_LOW) {
        gpio_ptr->DATA &= ~handle->pinmask;
    }
    else if (out_value == LWGPIO_VALUE_HIGH) {
        gpio_ptr->DATA |= handle->pinmask;
    }
    else { /* LWGPIO_VALUE_NOCHANGE or other value */
    }
   
}


/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_toggle_value
* Returned Value   : void
* Comments         :
*    Toggles value of output latch of the pin
*
*END*********************************************************************/
void lwgpio_toggle_value
(
    /* Pin handle to toggle value on */
    LWGPIO_STRUCT_PTR  handle
)
{
    lwgpio_set_value(handle, lwgpio_get_value(handle) == LWGPIO_VALUE_HIGH ? LWGPIO_VALUE_LOW : LWGPIO_VALUE_HIGH);
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_get_value
* Returned Value   : LWGPIO_VALUE of pin status
* Comments         :
*    Returns value (output latch or read data) of the pin
*
*END*********************************************************************/
LWGPIO_VALUE lwgpio_get_value
(
    /* Pin handle to get value from */
    LWGPIO_STRUCT_PTR  handle
)
{
    return (gpio_ptr->DATA & handle->pinmask) ? LWGPIO_VALUE_HIGH : LWGPIO_VALUE_LOW;
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_get_raw
* Returned Value   : LWGPIO_VALUE of pin status
* Comments         :
*    Returns read level of the pin
*
*END*********************************************************************/
LWGPIO_VALUE lwgpio_get_raw
(
    /* Pin handle to get value from */
    LWGPIO_STRUCT_PTR  handle
)
{
   return (gpio_ptr->DATA & handle->pinmask )? LWGPIO_VALUE_HIGH : LWGPIO_VALUE_LOW;
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_int_init
* Returned Value   : TRUE if succesfull, FALSE otherwise
* Comments         :
*    Initializes pin to generate interrupt
*
*END*********************************************************************/
boolean lwgpio_int_init
(
    /* Pin handle to initialize interrupt on */
    LWGPIO_STRUCT_PTR handle,
    /* Interrupt mode */
    LWGPIO_INT_MODE   mode
)
{ /* Body */

   if(mode == LWGPIO_INT_MODE_FALLING)   
      gpio_ptr->ICR |= handle->pinmask;
   else
      gpio_ptr->ICR &= ~handle->pinmask;
    return TRUE;
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_int_enable
* Returned Value   : void
* Comments         :
*    Enables / disables interrupts for specified pin
*
*END*********************************************************************/
void lwgpio_int_enable
(
    /* Pin handle to enable interrupt on */
    LWGPIO_STRUCT_PTR handle,
    /* Enable or disable interrupt? TRUE = enable */
    boolean           ena
)
{ /* Body */
    if (ena) {
        /* enable pin interrupts */
      gpio_ptr->IMR  |= handle->pinmask;
      _mpc83xx_enable_interrupt(MPC83xx_GPIO1_VECTOR);
   }
    else {
        /* disable pin interrupts */
       gpio_ptr->IMR  &= ~handle->pinmask;
       _mpc83xx_disable_interrupt(MPC83xx_GPIO1_VECTOR);
    }
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_int_get_flag
* Returned Value   : TRUE if interrupt flag is set
* Comments         :
*    Checks if there is pending interrupt flag for specified pin
*
*END*********************************************************************/
boolean lwgpio_int_get_flag
(
    /* Pin handle to get interrupt flag on */
    LWGPIO_STRUCT_PTR handle
)
{ /* Body */
   return  (gpio_ptr->IER & handle->pinmask)  ? TRUE : FALSE;
}

/*FUNCTION*****************************************************************
* 
* Function Name    : lwgpio_int_clear_flag
* Returned Value   : void
* Comments         :
*    Clears pending interrupt flag on peripheral
*
*END*********************************************************************/
void lwgpio_int_clear_flag
(
    /* Pin handle to clear interrupt flag on */
    LWGPIO_STRUCT_PTR handle
)
{ /* Body */
    /* Clear interrupt flag. Note that if an interrupt was acknowledged by NVIC,
    it will generate interrupt anyway. Interrupts on NVIC are grouped for each
    port */
    gpio_ptr->IER |= handle->pinmask;
}

/*FUNCTION****************************************************************
* 
* Function Name    : lwgpio_int_get_vector
* Returned Value   : pointer to base of GPIO registers
* Comments         :
*    This function returns base address of GPIO related register space.
*
*END*********************************************************************/
uint_32 lwgpio_int_get_vector
(
    /* Pin handle to get vector of */
    LWGPIO_STRUCT_PTR  handle
)
{
    return MPC83xx_GPIO1_VECTOR;
}

/* EOF */
